package com.sloth.bear.service.impl;

import com.sloth.bear.dto.vo.FileUploadVo;
import com.sloth.bear.service.FileService;
import com.sloth.bear.service.OssStorageService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import java.security.MessageDigest;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;

@Slf4j
@Service
@RequiredArgsConstructor
public class FileServiceImpl implements FileService {

    private final OssStorageService ossStorageService;

    /**
     * 最大文件大小：10MB
     */
    private static final long MAX_FILE_SIZE = 10 * 1024 * 1024;

    @Override
    public FileUploadVo uploadFile(MultipartFile file, String directory, Boolean isRename) {
        // 文件校验
        validateFile(file);

        try {
            // 生成文件路径和名称
            String filePath = generateFilePath(file, directory, isRename);

            // 上传到OSS
            String fileUrl = ossStorageService.upload(file, filePath);

            // 返回上传结果
            return new FileUploadVo(
                    file.getOriginalFilename(),
                    fileUrl,
                    file.getSize(),
                    file.getContentType(),
                    LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"))
            );

        } catch (Exception e) {
            log.error("上传文件失败", e);
            throw new RuntimeException("上传文件失败: " + e.getMessage());
        }
    }

    /**
     * 校验上传的文件
     */
    private void validateFile(MultipartFile file) {
        if (file == null || file.isEmpty()) {
            throw new IllegalArgumentException("上传文件不能为空");
        }

        if (file.getSize() > MAX_FILE_SIZE) {
            throw new IllegalArgumentException("文件大小不能超过10MB");
        }

        String contentType = file.getContentType();
        if (contentType == null) {
            throw new IllegalArgumentException("无法识别文件类型");
        }
    }

    /**
     * 生成文件存储路径
     * 格式: {directory}/md5.jpg
     * 使用文件MD5值作为文件名，相同文件会覆盖
     *
     * @param file      上传文件
     * @param directory 目录名称，如果为空则使用default
     * @return 文件路径
     */
    private String generateFilePath(MultipartFile file, String directory, Boolean isRename) {
        String originalFilename = file.getOriginalFilename();
        if (originalFilename == null) {
            throw new IllegalArgumentException("文件名不能为空");
        }

        // 如果目录为空或空白，使用default
        if (directory == null || directory.trim().isEmpty()) {
            directory = "default";
        }

        // 获取文件扩展名
        String extension = "";
        int lastDotIndex = originalFilename.lastIndexOf('.');
        if (lastDotIndex > 0) {
            extension = originalFilename.substring(lastDotIndex);
        }

        // 计算文件MD5值作为文件名
        String md5Hash = calculateMD5(file);
        String filename = Boolean.FALSE.equals(isRename) ? originalFilename : (md5Hash + extension);

        // 返回路径，不带开头的斜杠
        return String.format("%s/%s", directory, filename);
    }

    /**
     * 计算文件的MD5值
     *
     * @param file 文件
     * @return MD5十六进制字符串
     */
    private String calculateMD5(MultipartFile file) {
        try {
            MessageDigest md = MessageDigest.getInstance("MD5");
            byte[] digest = md.digest(file.getBytes());

            // 转换为十六进制字符串
            StringBuilder sb = new StringBuilder();
            for (byte b : digest) {
                sb.append(String.format("%02x", b));
            }
            return sb.toString();
        } catch (Exception e) {
            log.error("计算文件MD5失败", e);
            throw new RuntimeException("计算文件MD5失败: " + e.getMessage());
        }
    }
}